 <?php
	

use \GatewayWorker\Lib\Gateway;

include_once(dirname(__DIR__) .'/Module/Verification.class.php');
include_once(dirname(__DIR__) .'/Module/Socket.class.php');
include_once(dirname(__DIR__) .'/Module/Redis.class.php');
require_once dirname(__DIR__) . '/base.class.model.php';
require_once __DIR__ . '/Mahjong.php';
class Public_Model extends Base_Model
{

	/************************
		protected function
	************************/

	//扣除房卡或退还房卡
	protected function balanceTicket($room_id, $account_id, $spend_ticket_count){
		$timestamp = time();
		$MMYSQL = $this->initMysql();
		$MMYSQL->update(Room_Ticket)->set("ticket_count", "ticket_count-".$spend_ticket_count)->where("account_id=".$account_id)->query();

		//获取流水账
		$balance = 0;
		$balance_where = 'account_id='.$account_id.' and is_delete=0';
		$balance_sql = 'select balance from '.Room_Ticket_Journal.' where '.$balance_where.' order by journal_id desc';

		$balance_query = $MMYSQL->query($balance_sql);
		if(is_array($balance_query) && count($balance_query) > 0 ){
			$balance = $balance_query[0]['balance'];
		}

		//添加到流水账
		$journal_array['create_time'] = $timestamp;
		$journal_array['create_appid'] = "aid_".$account_id;
		$journal_array['update_time'] = $timestamp;
		$journal_array['update_appid'] = "aid_".$account_id;
		$journal_array['is_delete'] = G_CONST::IS_FALSE;
		$journal_array['account_id'] = $account_id;
		$journal_array['object_id'] = $room_id;
		$journal_array['object_type'] = 3;  //游戏

		$journal_array['extra'] = "";

		if($spend_ticket_count > 0){
			$journal_array['disburse'] = $spend_ticket_count;
			$journal_array['abstract'] = "麻将";		//摘要
		} else {
			$journal_array['income'] = -$spend_ticket_count;
			$journal_array['abstract'] = "麻将房卡退还";		//摘要
		}

		$journal_array['balance'] = $balance - $spend_ticket_count;
		if($journal_array['balance'] < 0)
		{
			$this->writeLog("balance negative balance: ".$balance." account_id: ".$account_id." room_id: ".$room_id);
			$journal_array['balance'] = 0;
		}
		$journal_id = $MMYSQL->insertReturnID(Room_Ticket_Journal,$journal_array);
	}


	//获取房间玩法设置
	protected function queryRoomSetting($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetallField($Room_Key);
		return $result;
	}

	//获取庄家用户id
	protected function queryBanker($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Banker);
		return $result;
	}
	//获取房主id
	protected function queryCreator($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Creator);
		return $result;
	}

	//新摸的牌
	public function queryNewCard($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_NewCard);
		return $result;
	}

	//获取鬼牌
	protected function queryJokerCard($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_JokerCard);
		return $result;
	}

	//承包风险
	public function queryLastUserDanger($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_InDanger);
		return $result == 1 ? 1 : 0;
	}

	//查询上一个打牌
	public function queryLastUserDiscard($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$mkv = array(Redis_Const::Play_Field_LastUser, Redis_Const::Play_Field_LastCard);
		$result = $Redis_Model->hmgetField($Play_Key, $mkv);
		if(is_array($result) ){
			$last_user    = $result[0] > 0 ? $result[0] : -1;
			$last_discard = $result[1] > 0 ? $result[1] : -1;
			return array('last_user'=>$last_user, 'last_discard'=>$last_discard);
		} else {
			return array('last_user'=> -1, 'last_discard'=> -1);
		}
	}

	//摸牌
	public function fetchOneCard($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RemainCard_Key = strtr(Redis_Const::RemainCard_Key, $replyArr);

		$card = $Redis_Model->popList(1 ,$RemainCard_Key,1);   //右边弹出一张

		$card = $card[0];

		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$mkv[Redis_Const::Play_Field_NewCard] = $card;
		$Redis_Model->hmsetField($Play_Key, $mkv);
		return $card;
	}

	public function queryRemainCardCount($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RemainCard_Key = strtr(Redis_Const::RemainCard_Key, $replyArr);

		$len = $Redis_Model->llenList($RemainCard_Key); 
		return $len;
	}



	public function queryRemainCard($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RemainCard_Key = strtr(Redis_Const::RemainCard_Key, $replyArr);

		$list = $Redis_Model->lrangeList($RemainCard_Key,0,-1); 
		if($list){
			return $list;
		} else {
			return array();
		}
	}
	public function setRemainCard($room_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RemainCard_Key = strtr(Redis_Const::RemainCard_Key, $replyArr);

		$result = $Redis_Model->pushList(0,0,$RemainCard_Key, $card);  //队尾 右边 下一张牌
		return $result;
	}

	//碰的牌
	public function queryPengCard($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){
			$Discard_Key = "PengCard:".$seat_number.":".$room_id;
			$list = $Redis_Model->lrangeList($Discard_Key,0,-1); 
			if($list){
				return $list;
			}
		} 
		return array();
	}
	//明杠牌
	public function queryMingGang($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){
			$Discard_Key = "MingGang:".$seat_number.":".$room_id;
			$list = $Redis_Model->lrangeList($Discard_Key,0,-1); 
			if($list){
				return $list;
			}
		} 
		return array();
	}
	//暗杠牌
	public function queryAnGang($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){
			$Discard_Key = "AnGang:".$seat_number.":".$room_id;
			$list = $Redis_Model->lrangeList($Discard_Key,0,-1); 
			if($list){
				return $list;
			}
		} 
		return array();
	}

	//打出的牌
	public function queryDiscard($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){
			$Discard_Key = "Discard:".$seat_number.":".$room_id;
			$list = $Redis_Model->lrangeList($Discard_Key,0,-1); 
			if($list){
				return $list;
			}
		} 
		return array();
	}
	//玩家手牌
	public function queryPlayerCard($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;
			$list = $Redis_Model->lrangeList($PlayerCard_Key,0,-1); 
			if($list){
				return $list;
			} 
		} 
		return array();
	}
	public function queryPlayerCardCount($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;
			$len = $Redis_Model->llenList($PlayerCard_Key); 
			return $len;
		} 
		return 0;
	}

	public function setPlayerCard($room_id, $account_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;

			//先清空队列
			$Redis_Model->deleteKey($PlayerCard_Key);	
			//再入队
			$hand_card = $card;
			sort($hand_card);
			$result = $Redis_Model->pushList(1,0,$PlayerCard_Key, $hand_card);

			//显示手牌
			$msg_arr = array(
				'result' => 0,
				'operation' => 'MyCard',
				'result_message' => "我的手牌",
				'data' => array(
					'my_card' => $card,
					)
				);
			$this->pushMessageToAccount($room_id, $account_id, $msg_arr);

			return $result;
		} else {
			return OPT_CONST::FAILED;
		}

	}

	public function pengFunc($room_id, $account_id, $is_passive=0){
		//上一个打牌
		$last_user_discard = $this->queryLastUserDiscard($room_id);
		$card = $last_user_discard['last_discard'];

		//更新当前出牌
		$this->removeDiscardToPeng($room_id, $account_id, $card);
			
		$msg_arr = array(
			'result' => 0,
			'operation' => 'Peng',
			'result_message' => "碰",
			'data' => array(
				'account_id' => $account_id,
				'card' => $card,
				'is_passive'=>$is_passive
				)
			);
		$this->pushMessageToGroup($room_id, $msg_arr);

		$result = $this->takeHisTurn($room_id, $account_id);
		$this->notyUserToChoose($room_id, $account_id, $has_new_card = false);
	}

	public function baoGangFunc($room_id, $account_id, $is_passive=0){

		//上一个打牌
		$last_user_discard = $this->queryLastUserDiscard($room_id);
		$last_user = $last_user_discard['last_user'];
		$card = $last_user_discard['last_discard'];

		$this->removeDiscardToGang($room_id, $account_id, $card);
		$this->balanceBaoGangScore($room_id, $account_id, $last_user);

		$msg_arr = array(
			'result' => 0,
			'operation' => 'Gang',
			'result_message' => "杠",
			'data' => array(
				'account_id' => $account_id,
				'card' => $card,
				'type' => 3,
				'is_passive'=>$is_passive
				)
			);
		$this->pushMessageToGroup($room_id, $msg_arr);

		$result = $this->takeHisTurn($room_id, $account_id);
		$this->notyUserToChoose($room_id, $account_id, $has_new_card = true);
	}

	public function anGangFunc($room_id, $account_id, $is_passive=0){
		$card = $this->queryNewCard($room_id);
		$hand_card = $this->queryPlayerCard($room_id, $account_id);
		//点数分析  
		$hand_card_count = count($hand_card);
		$gang_array = array();
		for($i=0; $i<$hand_card_count; $i++)  
		{  
			$sameCnt=1;  
			//搜索同牌  
			for($j=$i+1; $j<$hand_card_count; $j++)  
			{  
				if($hand_card[$j] != $hand_card[$i]){
					break;  
				} 
				$sameCnt++;  
			}  

			//设置结果  
			if($sameCnt == 4)  
			{  
				$gang_array[]=$hand_card[$i];
			} else if($sameCnt == 3 && $hand_card[$i] == $card){
				array_unshift($gang_array, $hand_card[$i]);  //优先
			} 
			//设置索引  
			$i += $sameCnt-1;  
		}  
		if(count($gang_array)>0){
			$card = $gang_array[0];
		}

		$this->removeCardToAnGang($room_id, $account_id, $card); //type 1暗杠  2加杠

		$this->balanceAnGangScore($room_id, $account_id);

		$msg_arr = array(
			'result' => 0,
			'operation' => 'Gang',
			'result_message' => "杠",
			'data' => array(
				'account_id' => $account_id,
				'card' => $card,
				'type' => 1
				)
			);
		$this->pushMessageToGroup($room_id, $msg_arr);

		$this->notyUserToChoose($room_id, $account_id, $has_new_card = true);
	}

	public function jiaGangFunc($room_id, $account_id, $is_passive=0){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);

		$card = $this->queryNewCard($room_id);

		$msg_arr = array(
			'result' => 0,
			'operation' => 'Gang',
			'result_message' => "杠",
			'data' => array(
				'account_id' => $account_id,
				'card' => $card,
				'type' => 2,  //加杠
				'is_passive' => $is_passive
				)
			);
		$this->pushMessageToGroup($room_id, $msg_arr);
		$this->removeNewCardToGang($room_id, $account_id, $card); //type 1暗杠  2加杠

		$qiang_array = array();

		$setting = $this->queryRoomSetting($room_id);
		$qianggang = $setting[Redis_Const::Room_Field_QiangGang];
		if($qianggang){
			$room_members = $this->queryRoomMembers($room_id);
			foreach ($room_members as $mem_id) {
				if($mem_id != $account_id){	//其他3家
					if($this->checkHu($room_id, $mem_id, $card) > 0){
						$qiang_array[] = $mem_id;
					}
				}
				
			}
		}

		if(count($qiang_array) > 0){

			$DaiQiangGang_Key = strtr(Redis_Const::DaiQiangGang_Key, $replyArr);
			$Redis_Model->saddSet($DaiQiangGang_Key, $qiang_array);

			$noty_arr = array(
				'account_id' => "",
				'playing_status' => Game::PlayingStatus_QiangGang,
				'limit_time'	 => Game::LimitTime_QiangGang,
				'card' => $card,
				);
			
			foreach ($qiang_array as $account_id) {
				$noty_arr['account_id'] = $account_id;
				$msg_arr = array("result"=>"0","operation"=>"NotyQiangGang","data"=>$noty_arr,"result_message"=>"通知抢杠");
				$this->pushMessageToAccount($room_id, $account_id, $msg_arr);
			}

			$room_members = $this->queryRoomMembers($room_id);
			$other = array_diff($room_members, $qiang_array);
			foreach ($other as $account_id) {
				$noty_arr = array(
					'account_id' => "",
					'playing_status' => Game::PlayingStatus_Waiting,
					'limit_time'	 => Game::LimitTime_QiangGang,
					);
				$msg_arr = array("result"=>"0","operation"=>"NotyQiangGang","data"=>$noty_arr,"result_message"=>"通知抢杠");
				$this->pushMessageToAccount($room_id, $account_id, $msg_arr);
			}

			$this->setupQiangGangPassiveTimer($room_id);

		} else {

			$this->balanceJiaGangScore($room_id, $account_id);
			//通知前端计分
			$msg_arr = array(
				'result' => 0,
				'operation' => 'JiaGangScore',
				'result_message' => "加杠计分",
				'data' => array(
					'account_id' => $account_id,
					'score' => $this->queryBaseScore($room_id)
					)
				);
			$this->pushMessageToGroup($room_id, $msg_arr);

			$this->notyUserToChoose($room_id, $account_id, $has_new_card = true);
		}
	}

	//设置最新出牌人
	protected function setLastUserTransaction($room_id,$update_account_id)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$redisAuth = $Redis_Model->pingRedisAuth();
		if($redisAuth === G_CONST::EMPTY_STRING || !is_object($redisAuth))
		{
			$this->logMessage('error', "function(setLastUserTransaction):redisAuth is empty string"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		$success = false;
		$options = array(
			'cas'   => true,    // Initialize with support for CAS operations
			'watch' => $key,    // Key that needs to be WATCHed to detect changes
			'retry' => 3,       // Number of retries on aborted transactions, after
								// which the client bails out with an exception.
		);

		$redisAuth->transaction($options, function ($tx) use ($key,$update_account_id, &$success) {
			$last_user_id = $tx->hget($key, Redis_CONST::Play_Field_LastUser);
			if (!isset($last_user_id) || $last_user_id != $update_account_id) {
				$tx->multi();   // With CAS, MULTI *must* be explicitly invoked.
				$tx->hmset($key, array(Redis_Const::Play_Field_LastUser => $update_account_id));
				$success =  true;

			} else {
				$this->logMessage('error', "function(setLastUserTransaction):last_user error ".$update_account_id." in file".__FILE__." on Line ".__LINE__);
				$success =  false;
			}
		});
		return $success;
	}

	public function removePlayerCardToDiscard($room_id, $account_id, $card){
		$update_account_id = $account_id;
		$success = $this->setLastUserTransaction($room_id,$update_account_id);
		if(!$success)
		{
			$this->logMessage('error',"function(removePlayerCardToDiscard):并发忽略，room id :".$room_id."in file".__FILE__."on Line".__LINE__);
			return OPT_CONST::FAILED;
		}

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);

		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){

			$new_card = $this->queryNewCard($room_id);
			if($new_card == $card){

			} else {
				$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;
				$list = $Redis_Model->lrangeList($PlayerCard_Key,0,-1); 
				if($list){
					foreach ($list as $key=>$value) {
						if($value == $card){
							$list[$key] = $new_card;
							break;
						}
					}
					sort($list);
					//先清空队列 再入队
					$Redis_Model->deleteKey($PlayerCard_Key);	
					$result = $Redis_Model->pushList(1,0,$PlayerCard_Key, $list);
				} 
			}
			//放到弃牌区
			$Discard_Key = "Discard:".$seat_number.":".$room_id;
			$result = $Redis_Model->pushList(1,0,$Discard_Key, [$card]);

			$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
			$mkv[Redis_Const::Play_Field_LastUser] = $account_id;
			$mkv[Redis_Const::Play_Field_LastCard] = $card;
			$mkv[Redis_Const::Play_Field_InDanger] = 0;
			$Redis_Model->hmsetField($Play_Key, $mkv);

			return $result;
		} else {
			return OPT_CONST::FAILED;
		}
	}

	public function removeDiscardToPeng($room_id, $account_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);

		//上一个打牌
		$last_user_discard = $this->queryLastUserDiscard($room_id);
		$last_user = $last_user_discard['last_user'];

		//从弃牌区取过来
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $last_user);
		if(in_array($seat_number, [1,2,3,4])){

			//PlayerCard
			$PlayerCard_Key = "Discard:".$seat_number.":".$room_id;
			$discard = $Redis_Model->popList(1, $PlayerCard_Key, 1);

			if($discard[0] != $card){
				$this->writeLog("[$room_id] ($account_id) 碰牌出错:".$discard[0]);
				return OPT_CONST::FAILED;
			} else {
				$this->writeLog("[$room_id] ($account_id)  碰牌:".$discard[0]);
			}

			//清空上一个打牌
			$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
			//$mkv[Redis_Const::Play_Field_LastUser] = -1;
			$mkv[Redis_Const::Play_Field_LastCard] = -1;
			$Redis_Model->hmsetField($Play_Key, $mkv);
		} else {
			return OPT_CONST::FAILED;
		}

		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){

			//PlayerCard
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;

			$cnt = $Redis_Model->lremList($PlayerCard_Key, 2, $card);

			$this->writeLog("[$room_id] ($account_id) 碰 从手牌中移除张数:".$cnt);
			
			//放到碰牌区
			$Discard_Key = "PengCard:".$seat_number.":".$room_id;
			$result = $Redis_Model->pushList(1,0,$Discard_Key, [$card]);
			return $result;
		} else {
			return OPT_CONST::FAILED;
		}
	}

	public function removeDiscardToGang($room_id, $account_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);

		$last_user_discard = $this->queryLastUserDiscard($room_id);
		$last_user = $last_user_discard['last_user'];

		//从弃牌区取过来
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $last_user);
		if(in_array($seat_number, [1,2,3,4])){

			//PlayerCard
			$PlayerCard_Key = "Discard:".$seat_number.":".$room_id;
			$discard = $Redis_Model->popList(1, $PlayerCard_Key, 1);

			if($discard[0] != $card){
				$this->writeLog("[$room_id] ($account_id) 杠牌出错:".$discard[0]);
				return OPT_CONST::FAILED;
			} else {
				$this->writeLog("[$room_id] ($account_id) 杠牌:".$discard[0]);
			}

			//清空上一个打牌
			$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
			//$mkv[Redis_Const::Play_Field_LastUser] = -1;
			$mkv[Redis_Const::Play_Field_LastCard] = -1;
			$mkv[Redis_Const::Play_Field_InDanger] = 1;
			$Redis_Model->hmsetField($Play_Key, $mkv);
		} else {
			return OPT_CONST::FAILED;
		}

		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){

			//PlayerCard
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;

			$cnt = $Redis_Model->lremList($PlayerCard_Key, 3, $card);

			$this->writeLog("[$room_id] ($account_id) 杠 从手牌中移除张数:".$cnt);
			
			//放到杠牌区
			$MingGang_Key = "MingGang:".$seat_number.":".$room_id;
			$result = $Redis_Model->pushList(1,0,$MingGang_Key, [$card]);
			return $result;
		} else {
			return OPT_CONST::FAILED;
		}
	}

	//type  1暗杠  
	public function removeCardToAnGang($room_id, $account_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);

		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){

			//PlayerCard
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;
			$cnt = $Redis_Model->lremList($PlayerCard_Key, 4, $card);
			$this->writeLog("[$room_id] ($account_id) 暗杠:".$card." 从手牌中移除张数:".$cnt);
			if($cnt == 4){	//自有暗杠，移除4张手牌后，还要插入新摸

				$list = $Redis_Model->lrangeList($PlayerCard_Key,0,-1); 
				if($list){
					$list[] = $this->queryNewCard($room_id);	//新摸的牌
					sort($list);
					//先清空队列 再入队
					$Redis_Model->deleteKey($PlayerCard_Key);	
					$result = $Redis_Model->pushList(1,0,$PlayerCard_Key, $list);
				} 
			}

			//放到杠牌区
			$AnGang_Key = "AnGang:".$seat_number.":".$room_id;
			$result = $Redis_Model->pushList(1,0,$AnGang_Key, [$card]);
			return $result;
		} else {
			return OPT_CONST::FAILED;
		}
	}

	//type 2加杠
	public function removeNewCardToGang($room_id, $account_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);

		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3,4])){

			$PengCard_Key = "PengCard:".$seat_number.":".$room_id;
			$cnt = $Redis_Model->lremList($PengCard_Key, 1, $card);
			$this->writeLog("[$room_id] ($account_id) 加杠:".$card." 移除碰牌数目:".$cnt);
			
			//放到杠牌区
			$MingGang_Key = "MingGang:".$seat_number.":".$room_id;
			$result = $Redis_Model->pushList(1,0,$MingGang_Key, [$card]);
			return $result;
		} else {
			return OPT_CONST::FAILED;
		}
	}


	protected function setHashTransaction($room_id)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$key = strtr(Redis_Const::Room_Key, $replyArr);

		$redisAuth = $Redis_Model->pingRedisAuth();
		if($redisAuth === G_CONST::EMPTY_STRING || !is_object($redisAuth))
		{
			$this->logMessage('error', "function(existsKey):redisAuth is empty string"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

	    $success = false;
	    $options = array(
	        'cas'   => true,    // Initialize with support for CAS operations
	        'watch' => $key,    // Key that needs to be WATCHed to detect changes
	        'retry' => 3,       // Number of retries on aborted transactions, after
	                            // which the client bails out with an exception.
	    );

	    $redisAuth->transaction($options, function ($tx) use ($key, &$success) {
	        $room_status = $tx->hget($key, Redis_Const::Room_Field_Status);
	        if (isset($room_status) && $room_status == 1) {
	            $tx->multi();   // With CAS, MULTI *must* be explicitly invoked.
	            $tx->hmset($key, array(Redis_Const::Room_Field_Status => 2));
	            $success =  true;

	        } else {
	        	$this->writeLog("room_status != 1");
	        	$success =  false;
	        }
	    });
	    return $success;
	}

	//开局
	protected function startGame($room_id)
	{
		$timestamp = time();
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		

		$ready_user = $this->queryReadyUser($room_id);
		$in_room_array = $this->queryInRoomUser($room_id);
		$ready_count = count($ready_user);
		$online_count = count($in_room_array);
			
		$this->writeLog("[$room_id] 准备:".$ready_count."人   "."在线:".$online_count."人");

		if($ready_count == 4)
		{
			if($ready_count == $online_count){


				$room_members = $this->queryRoomMembers($room_id);

				$readyUser_ary = array();
				foreach($room_members as $account_id)
				{
					$ready_count ++;
					$readyUser_ary[] = $account_id;
				}

				$success = $this->setHashTransaction($room_id);
				if(!$success){
					$this->writeLog("并发 start game，忽略。room id:".$room_id."。in file".__FILE__." on Line ".__LINE__);
					return false;
				}

				if(Config::Room_AutoBreak){
					//取消倒计时(自动解散房间定时器)
					$this->deleteRoomTimer($room_id);
				}

				//开始游戏
				//扣房卡
				$ticket_checked_user = $this->queryTicketCheckedUser($room_id);
				$to_check_user_array = array_diff($readyUser_ary, $ticket_checked_user);
				if(count($to_check_user_array) > 0){

					$setting = $this->queryRoomSetting($room_id);
					$spend_ticket_count=isset($setting[Redis_Const::Room_Field_TicketCount]) ?$setting[Redis_Const::Room_Field_TicketCount]:1;

					foreach ($to_check_user_array as $account_id) {
						
						if(Config::Ticket_Mode == 1){
							//扣除房卡
							$this->balanceTicket($room_id, $account_id, $spend_ticket_count);
						}
						$mkv[$account_id] = 1;
					}

					$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
					$Redis_Model->hmsetField($TicketChecked_Key,$mkv);
				}

				//房间轮数与局数更新
				$this->updateGameNumberRound($room_id);

				$this->initGame($room_id, $readyUser_ary);

			} 
		}
		
		return true;
	}

	//开局
	protected function initGame($room_id, $readyUser_ary=array())
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		
		//设置每局玩家顺序list
		$banker_id = $this->queryBanker($room_id);
		$banker_id = $banker_id > 0 ? $banker_id : $this->queryCreator($room_id);
		if($banker_id > 0){

			$offset = array_search($banker_id, $readyUser_ary);
			if($offset !== false){

			} else {
				$offset = 0;
			}

		} else {
			$offset = 0;
		}
		$play_member = array_merge(array_slice($readyUser_ary, $offset), array_slice($readyUser_ary,0,$offset));

		$next_banker_id = $play_member[0];

		//开始游戏				
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);

		$RemainCard_Key = strtr(Redis_Const::RemainCard_Key, $replyArr);
		
		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);	//本局输赢
		
		//删除每局玩家手牌hash
		for ($i=1; $i <= 4; $i++) { 
			$Redis_Model->deleteKey("PlayerCard:".$i.":".$room_id);
			$Redis_Model->deleteKey("PengCard:".$i.":".$room_id);
			$Redis_Model->deleteKey("MingGang:".$i.":".$room_id);
			$Redis_Model->deleteKey("AnGang:".$i.":".$room_id);
			$Redis_Model->deleteKey("Discard:".$i.":".$room_id);
		}
		$Redis_Model->deleteKey($RemainCard_Key);
		$Redis_Model->deleteKey($Chip_Key);
		
		//删除每局玩家顺序list
		$Redis_Model->deleteKey($PlayMember_Key);
		$DaiQiangGang_Key = strtr(Redis_Const::DaiQiangGang_Key, $replyArr);
		$YiQiangGang_Key = strtr(Redis_Const::YiQiangGang_Key, $replyArr);
		$Redis_Model->deleteKey($DaiQiangGang_Key);
		$Redis_Model->deleteKey($YiQiangGang_Key);
		
		$AccountStatus_mvk = array();
		$Chip_mvk = array();

		$player_cards = $this->dealCard($room_id);  //发牌
		
		for ($i=0; $i < 4; $i++) 
		{
			$account_id = $play_member[$i];
			$AccountStatus_mvk[$account_id] = Game::AccountStatus_Play;
			$Chip_mvk[$account_id] = 0;
		}
		//设置剩余牌
		$this->setRemainCard($room_id, $player_cards[4]);

		//鬼牌
		$flip_card = $player_cards[5];
		$joker_card = $player_cards[6];

		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $play_member[3]);
		if(in_array($seat_number, [1,2,3,4])){
			$Discard_Key = "Discard:".$seat_number.":".$room_id;
			$result = $Redis_Model->pushList(1,0,$Discard_Key, [$flip_card]);
		}

		//玩家队列
		$Redis_Model->hmsetField($Chip_Key,$Chip_mvk);
		$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$AccountStatus_mvk);
		$push_result = $Redis_Model->pushList($is_rpush=0,$is_pushx=0,$PlayMember_Key,$play_member); //lpush
		
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$Room_mkv[Redis_CONST::Room_Field_Status] = 2;  //房间状态，1等待、2进行中、3关闭
		$Room_mkv[Redis_CONST::Room_Field_Banker] = $next_banker_id;	//庄家
		$mset_result = $Redis_Model->hmsetField($Room_Key,$Room_mkv);

		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$Play_mkv[Redis_CONST::Play_Field_JokerCard] = $joker_card;	
		$mset_result = $Redis_Model->hmsetField($Play_Key,$Play_mkv);

		//推送开始
		$gnum = $this->queryGameNumber($room_id);
		$msg_arr = array("result"=>0,"operation"=>"GameStart","data"=>array('game_num'=>$gnum,'flip_card'=>$flip_card,'joker_card'=>$joker_card, 'banker_id'=>$next_banker_id),"result_message"=>"游戏开始");

		$this->pushMessageToGroup($room_id, $msg_arr); 

		//设置玩家手牌
		for ($i=0; $i < 4; $i++) 
		{
			$account_id = $play_member[$i];
			$this->setPlayerCard($room_id, $account_id, $player_cards[$i]);
		}

		$next_account_id = $this->takeTurns($room_id);
		$this->notyUserToChoose($room_id, $next_account_id, $has_new_card = true, $is_first=true);

		return true;
	}


	/*
		发牌	 
	*/ 
	public function dealCard($room_id){
	
		$setting = $this->queryRoomSetting($room_id);
		$joker = $setting[Redis_Const::Room_Field_Joker];
		$Card = array();

		for ($repeat=0; $repeat < 4; $repeat++) { 

			for ($i=1; $i <= 9; $i++) { //萬
				$Card[] = 120 + $i;
			}
			for ($i=1; $i <= 9; $i++) { //条
				$Card[] = 140 + $i;
			}
			for ($i=1; $i <= 9; $i++) { //饼
				$Card[] = 160 + $i;
			}

			//东南西北 发白
    		if($joker != 3){   //joker 3 无风
				$Card[] = 180;	
				$Card[] = 183;	
				$Card[] = 186;
				$Card[] = 189;
	
				$Card[] = 196;
				$Card[] = 199;
			}

			if($joker == 0 || $joker == 1){   //joker 0无鬼牌  1翻牌当鬼
				$Card[] = 193;
			} else { 	 //joker == 2
				$Card[] = 93; //红中作赖子牌
			}

		}
        mt_srand();
		shuffle($Card);

		if($joker == 1){
			$flip_card = array_pop($Card);
			$type = intval($flip_card/10);
			$zi = array(180,183,186,189,193,196,199);
			if( $type == 12 || $type == 14 || $type == 16){
				$value = $flip_card % 10;
				$joker_card = $type * 10 + ($value % 9 + 1);
			} else if( ($index = array_search($flip_card, $zi)) !== false ){
				$index = ($index + 1) % 7;
				$joker_card = $zi[$index];
			} else {
				$this->writeLog("function(dealCard):翻出来的是什么东东($flip_card)"." in file".__FILE__." on Line ".__LINE__);
			}

			array_walk($Card, function(&$value) use ($joker_card) {
				if($value == $joker_card){
					$value -= 100; 
				}
			});

		} else {
			$flip_card = "";
			$joker_card = "";
		}

		$index = 0;
		$card1 = array();
		$card2 = array();
		$card3 = array();
		$card4 = array();

		for ($i=0; $i < 3; $i++) { 
			array_push($card1, $Card[$index], $Card[$index+1], $Card[$index+2], $Card[$index+3]);
			$index += 4;
			array_push($card2, $Card[$index], $Card[$index+1], $Card[$index+2], $Card[$index+3]);
			$index += 4;
			array_push($card3, $Card[$index], $Card[$index+1], $Card[$index+2], $Card[$index+3]);
			$index += 4;
			array_push($card4, $Card[$index], $Card[$index+1], $Card[$index+2], $Card[$index+3]);
			$index += 4;
		}
		$card1[] = $Card[$index++];
		$card2[] = $Card[$index++];
		$card3[] = $Card[$index++];
		$card4[] = $Card[$index++];
		$public_cards = array_slice($Card, $index);
		return array($card1, $card2, $card3, $card4, $public_cards, $flip_card, $joker_card);
	}

	/*
		发牌	 
	*/ 
	public function dealCard1($room_id){

		$card1 = array();
		$card2 = array();
		$card3 = array();
		$card4 = array();
		for ($i=0; $i < 3; $i++) { 
			array_push($card1, 121, 122, 123, 124);
			array_push($card2, 141, 142, 143, 144);
			array_push($card3, 161, 162, 163, 164);
			array_push($card4, 180, 183, 186, 189);
		}
		$card1[] = 125;
		$card2[] = 145;
		$card3[] = 165;
		$card4[] = 193;
		$public_cards = array();

		for ($repeat=0; $repeat < 4; $repeat++) { 

			for ($i=6; $i <= 9; $i++) { //萬
					$public_cards[] = 120 + $i;
			}
			for ($i=6; $i <= 9; $i++) { //条
					$public_cards[] = 140 + $i;
			}
			for ($i=6; $i <= 9; $i++) { //饼
					$public_cards[] = 160 + $i;
			}

			//东南西北中发白
			array_push($public_cards, 180,183,186,189,193,196,199);
		}
		$flip_card = "";
		$joker_card = "";

		return array($card1, $card2, $card3, $card4, $public_cards, $flip_card, $joker_card);
	}

	/*
		发牌	 
	*/ 
	public function dealCard2($room_id){

		$card1 = array();
		$card2 = array();
		$card3 = array();
		$card4 = array();
		array_push($card1, 127, 129, 141,142,143,144,145,146,147,148,149,161,161);
		array_push($card2, 121, 121, 123,124,125,126,127,128,180,183,186,189,199);
		array_push($card3, 122, 123, 141,142,143,144,145,146,147,148,149,161,161);
		array_push($card4, 122, 123, 141,142,143,144,145,146,147,148,149,161,161);
		
		$public_cards = array();
		array_push($public_cards, 121,183,186,189,121);
		for ($repeat=0; $repeat < 4; $repeat++) { 

			for ($i=6; $i <= 9; $i++) { //萬
					$public_cards[] = 120 + $i;
			}
			for ($i=6; $i <= 9; $i++) { //条
					$public_cards[] = 140 + $i;
			}
			for ($i=6; $i <= 9; $i++) { //饼
					$public_cards[] = 160 + $i;
			}
			//东南西北中发白
			array_push($public_cards, 180,183,186,189,193,196,199);
		}
		$flip_card = "";
		$joker_card = "";

		return array($card1, $card2, $card3, $card4, $public_cards, $flip_card, $joker_card);
	}

	public function dealCard3($room_id){

		$card1 = array();
		$card2 = array();
		$card3 = array();
		$card4 = array();
		array_push($card1, 127, 129, 141,142,143,144,145,146,147,148,149,162,162);
		array_push($card2, 121, 121, 123,124,125,126,127,128,180,183,186,189,199);
		array_push($card3, 122, 123, 141,142,143,144,145,146,148,148,148,161,161);
		array_push($card4, 122, 123, 141,142,143,144,145,146,147,147,147,161,161);
		
		$public_cards = array();
		array_push($public_cards, 162,121,121,189,169);
		for ($repeat=0; $repeat < 4; $repeat++) { 

			for ($i=6; $i <= 9; $i++) { //萬
					$public_cards[] = 120 + $i;
			}
			for ($i=6; $i <= 9; $i++) { //条
					$public_cards[] = 140 + $i;
			}
			for ($i=6; $i <= 9; $i++) { //饼
					$public_cards[] = 160 + $i;
			}
			//东南西北中发白
			array_push($public_cards, 180,183,186,189,193,196,199);
		}
		$flip_card = "";
		$joker_card = "";

		return array($card1, $card2, $card3, $card4, $public_cards, $flip_card, $joker_card);
	}



	//设置 自动出牌 定时器
	protected function setupChooseCardPassiveTimer($room_id, $account_id, $is_first=false){

		if(!$is_first){
			$limit_time = Game::LimitTime_Choosing;
		} else {
			$setting = $this->queryRoomSetting($room_id);
			$joker = isset($setting[Redis_Const::Room_Field_Joker])?$setting[Redis_Const::Room_Field_Joker]:0;
			$limit_time = $joker == 1 ? Game::LimitTime_Choosing + 8 :  Game::LimitTime_Choosing + 4 ;
		}

		$callback_array = array(
			'operation' => "ChooseCardPassive",
			'room_id' => $room_id,
			'data' => array(
				'account_id' => $account_id
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => $limit_time,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 自动碰杠 定时器
	protected function setupPengGangPassiveTimer($room_id, $account_id){

		$callback_array = array(
			'operation' => "PengGangPassive",
			'room_id' => $room_id,
			'data' => array(
				'account_id' => $account_id
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_PengGang,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 自动抢杠 定时器
	protected function setupQiangGangPassiveTimer($room_id){

		$callback_array = array(
			'operation' => "QiangGangPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_QiangGang,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 清理房间 定时器
	protected function setupClearRoomPassiveTimer($room_id){

		$this->writeLog("[$room_id] 设置了自动打扫房间定时器");
		$callback_array = array(
			'operation' => "ClearRoomPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_ClearRoom,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 解散房间 定时器
	protected function setupBreakRoomPassiveTimer($room_id){

		$this->writeLog("[$room_id] 设置了自动解散房间定时器");
		$callback_array = array(
			'operation' => "BreakRoomPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_BreakRoom,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//取消定时器
	protected function deleteRoomTimer($room_id){

		$timer_id = $this->queryTimerId($room_id);
		if($timer_id > 0){
			$arr = array(
				'operation' => "DeleteTimer",
				'room_id'   => $room_id,
				'data' => array(
					'timer_id' => $timer_id
					)

				);
			$this->sendToTimerServer($arr);
		}
		$this->updateTimer($room_id, -1);
	}



	//查询倒计时
	protected function queryCountdown($room_id, $limit){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$timer_time = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_TimerTime);
		if($timer_time > 0){
			$countdown = $limit - time() + $timer_time;
			return $countdown > 0 ? $countdown : 0;
		} else {
			return $limit;
		}
	}


	//设置或取消(timer_id  -1)定时器
	protected function updateTimer($room_id, $timer_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$mkv[Redis_Const::Play_Field_TimerId] = $timer_id;
		if($timer_id > 0){
			$mkv[Redis_Const::Play_Field_TimerTime] = time();
		} else {
			$mkv[Redis_Const::Play_Field_TimerTime] = -1;
		}

		$mset_result = $Redis_Model->hmsetField($Play_Key,$mkv);
	}


	//获取定时器id
	protected function queryTimerId($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_TimerId);
		return $result;
	}

	//更新房间状态
	protected function updateRoomStatus($room_id, $status){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$mkv[Redis_Const::Room_Field_Status] = $status;
		$mset_result = $Redis_Model->hmsetField($Room_Key,$mkv);
	}

	//重新设置所有用户状态为未准备
	protected function resetAllAccountStatus($room_id, $reset_status=Game::AccountStatus_Notready){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);

		$mkv = array();
		$members = $this->queryRoomMembers($room_id);
		if(is_array($members) && count($members)){
			foreach ($members as $account_id) {
				$pre_status = $this->queryAccountStatus($room_id, $account_id);
				$status = ($pre_status == Game::AccountStatus_Initial) ? Game::AccountStatus_Initial : $reset_status;

				$mkv[$account_id] = $status;
			}
		}
		$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$mkv);  //用户状态
	}

	//重新设置所有用户分数为0
	protected function resetAllAccountScore($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);

		$mkv = array();
		$members = $this->queryRoomMembers($room_id);
		if(is_array($members) && count($members)){
			foreach ($members as $account_id) {
				$mkv[$account_id] = 0;
			}
		}
		$mset_result = $Redis_Model->hmsetField($RoomScore_Key,$mkv);  //用户状态
	}

	//获取房间用户有序集合
	protected function queryRoomMembers($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$zrange_array['is_zrange'] = true;
		$zrange_array['key'] = $RoomSequence_Key;
		$zrange_array['start'] = 0;
		$zrange_array['stop'] = -1;
		$members = $Redis_Model->zrangeSet($zrange_array);
		
		if(is_array($members)){
			return $members;
		} else {
			return array();
		}
		
	}

	//获取房间状态
	protected function queryRoomStatus($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Status);
		return $result;
	}

	//获取房间每轮需要消耗的房卡数
	protected function queryTicketCount($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_TicketCount);
		return $result > 0 ? $result : 1;
	}

	//获取房间一轮总局数
	protected function queryTotalNum($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_TotalNum);
		return $result;
	}

	//获取房间当前局数
	protected function queryGameNumber($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_GameNum);
		return $result;
	}

	//自增长房间当前局数、轮数
	protected function updateGameNumberRound($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$game_num = $Redis_Model->hincrbyField($Room_Key, Redis_Const::Room_Field_GameNum, 1);
		$this->writeLog("[$room_id] 新的一局 :".$game_num);

		if($game_num == 1){
			//设置开局时间
			$this->updateStartTime($room_id);
		}
	}

	//更新用户状态
	protected function updateAccountStatus($room_id, $account_id, $status){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$mkv[$account_id] = $status;
		$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$mkv);

		//广播用户状态改变
		$noty_arr = array(
			'account_id' => $account_id,
			'account_status'=>$status,
			'online_status'=>$this->queryOnlineStatus($room_id, $account_id)
			);
		$this->writeLog("[$room_id] ($account_id)  状态改变 ". $status);
		$this->notyUpdateAccountStatusToGroup($room_id, $noty_arr);
	}

	//获取在线状态
	protected function queryOnlineStatus($room_id, $account_id){
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$RoomUser_UID = strtr(Game::RoomUser_UID, $replyArr);

		return Gateway::isUidOnline($RoomUser_UID);
	}


	//获取准备人数
	protected function queryReadyCount($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$result = $Redis_Model->hgetallField($AccountStatus_Key);
		$count = 0;
		if(Redis_CONST::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == Game::AccountStatus_Ready){
					$count++;
				}
			}
		}
		return $count;
	}

	//获取准备的人
	protected function queryReadyUser($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$ready_user_array = [];
		$result = $Redis_Model->hgetallField($AccountStatus_Key);
		if(Redis_CONST::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == Game::AccountStatus_Ready){
					$ready_user_array[] = $account_id;
				}
			}
		}
		return $ready_user_array;
	}
	//获取在房的人
	protected function queryInRoomUser($room_id){
		$in_room_user_array = [];
		$room_members = $this->queryRoomMembers($room_id);

		foreach ($room_members as $account_id) {
			if($this->queryOnlineStatus($room_id, $account_id)){
				$in_room_user_array[] = $account_id;
			}
		}
		return $in_room_user_array;
	}

	//获取用户地理
	protected function queryAccountGeo($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::Geo_Key, $replyArr);
		$result = $Redis_Model->hgetField($AccountStatus_Key,$account_id);
		if($result){
			$arr = explode(",", $result);
			$longitude=$arr[0];
			$latitude=$arr[1];
		} else {
			$longitude='';
			$latitude='';
		}
		return array('longitude'=>$longitude, 'latitude'=>$latitude);
	}
	//设置用户地理
	protected function updateAccountGeo($room_id, $account_id, $longitude, $latitude){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Geo_Key = strtr(Redis_Const::Geo_Key, $replyArr);

		if($longitude && $latitude){
			$result = $Redis_Model->hmsetField($Geo_Key, [$account_id => $longitude.','.$latitude]);
		} else {
			$result = $Redis_Model->hmsetField($Geo_Key, [$account_id => '']);
		}
		return $result;
	}


	//获取扣除了房卡的人
	protected function queryTicketCheckedUser($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
		
		$user_array = [];
		$result = $Redis_Model->hgetallField($TicketChecked_Key);
		if(Redis_CONST::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == 1){
					$user_array[] = $account_id;
				}
			}
		}
		return $user_array;
	}

	//获取用户是否已经扣除房卡
	protected function queryTicketChecked($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
		$result = $Redis_Model->hgetField($TicketChecked_Key,$account_id);
		return $result == 1 ? 1 : 0;
	}

	//获取用户状态
	protected function queryAccountStatus($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($AccountStatus_Key,$account_id);
		return $result;
	}

	//获取用户积分
	protected function queryAccountScore($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($RoomScore_Key,$account_id);
		return $result;
	}

	//下注平衡积分
	protected function balanceScore($room_id, $account_id, $score){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$mset_result = $Redis_Model->hincrbyField($RoomScore_Key,$account_id, 0 - $score); //总分 减少
		$mset_result = $Redis_Model->hincrbyField($Play_Key,Redis_Const::Play_Field_PoolScore, $score);	//分数池 增加
	}



	//暗杠杠平衡积分
	protected function balanceAnGangScore($room_id, $winner_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);

		$base_score = $this->queryBaseScore($room_id);
		$score =$base_score*2 ;
		$room_members = $this->queryRoomMembers($room_id);
		foreach ($room_members as $mem_id) {
			if($mem_id == $winner_id){
				$Redis_Model->hincrbyField($RoomScore_Key, $mem_id, $score * 3);
				$Redis_Model->hincrbyField($Chip_Key, $mem_id, $score * 3);
			} else {
				$Redis_Model->hincrbyField($RoomScore_Key, $mem_id,  - $score );
				$Redis_Model->hincrbyField($Chip_Key, $mem_id,  - $score );
			}
		}
	}
	//加杠平衡积分
	protected function balanceJiaGangScore($room_id, $winner_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);

		$base_score = $this->queryBaseScore($room_id);
		$score =$base_score*1 ;
		$room_members = $this->queryRoomMembers($room_id);
		foreach ($room_members as $mem_id) {
			if($mem_id == $winner_id){
				$Redis_Model->hincrbyField($RoomScore_Key, $mem_id, $score * 3);
				$Redis_Model->hincrbyField($Chip_Key, $mem_id, $score * 3);
			} else {
				$Redis_Model->hincrbyField($RoomScore_Key, $mem_id,  - $score );
				$Redis_Model->hincrbyField($Chip_Key, $mem_id,  - $score );
			}
		}
	}

	//放杠杠平衡积分
	protected function balanceBaoGangScore($room_id, $winner_id, $loser_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);

		$base_score = $this->queryBaseScore($room_id);

		$Redis_Model->hincrbyField($RoomScore_Key, $winner_id,  $base_score * 3 );
		$Redis_Model->hincrbyField($RoomScore_Key, $loser_id,   - $base_score * 3);
		//当局分数
		$Redis_Model->hincrbyField($Chip_Key, $winner_id,  $base_score * 3 );
		$Redis_Model->hincrbyField($Chip_Key, $loser_id,   - $base_score * 3);
	}

	


	//抢杠平衡积分
	protected function balanceQiangScore($room_id, $winner_id, $loser_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);

		$loser_id = $this->queryActiveUser($room_id);

		$base_score = $this->queryBaseScore($room_id);

		$Redis_Model->hincrbyField($RoomScore_Key, $winner_id,  $base_score * 6 );
		$Redis_Model->hincrbyField($RoomScore_Key, $loser_id,   - $base_score * 6);
		//当局分数
		$Redis_Model->hincrbyField($Chip_Key, $winner_id,  $base_score * 6 );
		$Redis_Model->hincrbyField($Chip_Key, $loser_id,   - $base_score * 6);

	}

	//返回积分榜
	protected function queryScoreboard($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Scoreboard);
		if($result !== Redis_Const::DATA_NONEXISTENT){
			$arr = json_decode($result);
		} else {
			$arr = new stdClass();
		}
		return $arr;
	}

	//返回上局输赢统计榜
	protected function queryScoreSummary($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);

		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);
		$result = $Redis_Model->hgetallField($Chip_Key);	//每局输赢
		
		if($result !== Redis_Const::DATA_NONEXISTENT){
			return $result;
		} else {
			$result = new stdClass();
		}
		return $result;
	}


	//获取当前倍数
	protected function queryMultiple($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_Multiple);
		return $result;
	}

	//获取底分分数
	protected function queryBaseScore($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_BaseScore);
		return $result;
	}


	//获取激活的操作中的用户
	protected function queryActiveUser($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_ActiveUser);
		return $result;
	}
	//获取开局时间
	protected function queryStartTime($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_StartTime);
		return  $result > 0 ? $result : -1;
	}
	//更新游戏开局时间
	protected function updateStartTime($room_id)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$mkv[Redis_Const::Room_Field_StartTime] = time();
		$mset_result = $Redis_Model->hmsetField($Room_Key,$mkv);
		return $mset_result;
	}

	//获取操作
	protected function queryActiveType($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_ActiveType);
		return $result;
	}

	//轮流到特定用户
	protected function takeHisTurn($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);

		$tmp_account_id = -1;
		for ($i=0; $i < 4; $i++) { 
			$tmp_account_id = $Redis_Model->rotationList($PlayMember_Key);
			if($tmp_account_id == $account_id){
				break;
			}
		}

		return $tmp_account_id;

	}


	//是否抢杠胡
	protected function queryQiangGang($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_QiangGang);
		return $result==1 ? 1: 0;
	}
	//设置抢杠胡
	protected function setQiangGang($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hmsetField($Play_Key, [Redis_Const::Play_Field_QiangGang => 1]);
	}

	//轮流
	protected function takeTurns($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
		$result = $Redis_Model->rotationList($PlayMember_Key);

		if($result > 0){
			$account_id = $result;
		} else {
			$account_id = -1;
		}

		return $account_id;
	}

	//获取游戏中的人数
	protected function queryPlayMemberCount($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
		$result = $Redis_Model->llenList($PlayMember_Key);
		return $result;
	}

	//推消息
	protected function pushMessageToGroup($room_id, $msg_arr, $exclude_client_id=null){
		$msg = $this->_JSON($msg_arr);
		Gateway::sendToGroup($room_id, $msg, $exclude_client_id);
	}
	protected function pushMessageToAccount($room_id, $account_id, $msg_arr){
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$RoomUser_UID = strtr(Game::RoomUser_UID, $replyArr);
		$msg = $this->_JSON($msg_arr);
		Gateway::sendToUid($RoomUser_UID, $msg);
	}
	protected function pushMessageToCurrentClient($msg_arr){
		$msg = $this->_JSON($msg_arr);
		Gateway::sendToCurrentClient($msg);
	}

	//广播用户状态改变
	protected function notyUpdateAccountStatusToGroup($room_id, $noty_arr, $exclude_client_id=null){

		if(!isset($noty_arr['account_id']) || !isset($noty_arr['account_status']) ){
			$this->writeLog("function(notyUpdateAccountStatusToGroup):lack of params"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		$msg_arr = array("result"=>"0","operation"=>"UpdateAccountStatus","data"=>$noty_arr,"result_message"=>"用户状态改变");
		$this->pushMessageToGroup($room_id, $msg_arr, $exclude_client_id=null);
	}

	/*
		检查有没有碰，有的话通知要碰的人
		参数 account_id 打牌人id
		      card  打出的牌
		返回 true有   false无
	*/
	protected function checkPeng($room_id, $account_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$playing_status = Game::PlayingStatus_Waiting;
		$next_noty_account_id = -1;

		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$zrange_array['is_zrange'] = true;
		$zrange_array['key'] = $RoomSequence_Key;
		$zrange_array['start'] = 0;
		$zrange_array['stop'] = -1;
		$zrange_array['WITHSCORES'] = true;
		$result = $Redis_Model->zrangeSet($zrange_array);
		if(is_array($result)){
			foreach ($result as $a_id => $seat_number) {
				if($a_id != $account_id){	//其他三家
					$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;
					$list = $Redis_Model->lrangeList($PlayerCard_Key,0,-1); 
					if($list){
						$same_count = 0;
						foreach ($list as $value) {
							if($value == $card){
								$same_count++;
							}
						}
						if($same_count == 3){
							$next_noty_account_id = $a_id;
							$playing_status = Game::PlayingStatus_Gang;
						} else if ($same_count == 2){
							$next_noty_account_id = $a_id;
							$playing_status = Game::PlayingStatus_Peng;
						}
					} 
				}
			}
		} else {
			$this->writeLog("[$room_id] ($account_id) function(checkPeng):获取不到其他三家牌");
			return false;
		}

		if($playing_status > Game::PlayingStatus_Waiting){
			$this->notyUserToPengGang($room_id, $next_noty_account_id, $playing_status);
			return true;
		} else {
			return false;
		}

	}



	//检查是否有杠  0无   1有暗杠   2有加杠
	protected function checkGang($room_id, $account_id, $new_card){

		$peng_card = $this->queryPengCard($room_id, $account_id);
		foreach ($peng_card as $value) {
			if($value == $new_card){
				return 2; //加杠
			}
		}

		$hand_card = $this->queryPlayerCard($room_id, $account_id);
		//点数分析  
		$hand_card_count = count($hand_card);
		$gang_array = array();
		for($i=0; $i<$hand_card_count; $i++)  
		{  
			$sameCnt=1;  
			//搜索同牌  
			for($j=$i+1; $j<$hand_card_count; $j++)  
			{  
				if($hand_card[$j] != $hand_card[$i]){
					break;  
				} 
				$sameCnt++;  
			}  

			//设置结果  
			if($sameCnt == 4)  
			{  
				$gang_array[]=$hand_card[$i];
			} else if($sameCnt == 3 && $hand_card[$i] == $new_card){
				$gang_array[]=$hand_card[$i]; //暗杠
			} 
			//设置索引  
			$i += $sameCnt-1;  
		}  
		if(count($gang_array)>0){
			return 1;	//暗杠
		}
		return 0;
	}

	

	protected function checkHu($room_id, $account_id, $new_card){

		$mahjong = Mahjong::instance();
		$cards = $this->queryPlayerCard($room_id, $account_id);
		$cards[] = $new_card;
		sort($cards);

		$win = $mahjong->checkCardHu($cards);
		if($win > 0){
			$this->writeLog("[$room_id] ($account_id) 胡牌结果: ".$win. "\n" .  "【". implode(",", $cards) ."】");
		}
		return $win;
	}

	//通知用户出牌
	protected function notyUserToChoose($room_id, $account_id, $has_new_card = true, $is_first=false){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$mkv[Redis_Const::Play_Field_ActiveUser] = $account_id;
		$mkv[Redis_Const::Play_Field_ActiveType] = Game::PlayingStatus_Choosing;
		$mset_result = $Redis_Model->hmsetField($Play_Key,$mkv);

		$remain_count = $this->queryRemainCardCount($room_id);
		if(0 == $remain_count){
			$this->showWin($room_id, -1); //流局
			return 0;
		}

		//设置自动出牌定时器
		$this->setupChooseCardPassiveTimer($room_id, $account_id, $is_first);
		$hu_flag = 0;
		$gang_flag = 0;
		if($has_new_card){
			
			$new_card = $this->fetchOneCard($room_id, $account_id);
			$this->writeLog("[$room_id] ($account_id) 摸牌(".$new_card.")");
			
			$hu_flag = $this->checkHu($room_id, $account_id, $new_card);
			
			$gang_flag = $this->checkGang($room_id, $account_id, $new_card);

		} else {
			$new_card = "";
		}
		
		$noty_arr = array(
			'account_id' => $account_id,
			'playing_status' => Game::PlayingStatus_Choosing,
			'limit_time'	 => Game::LimitTime_Choosing,
			'remain_count' => $remain_count,
			'new_card' => $new_card,
			'hu_flag' => $hu_flag,
			'gang_flag' => $gang_flag,
			);
		$msg_arr = array("result"=>"0","operation"=>"NotyChooseCard","data"=>$noty_arr,"result_message"=>"通知出牌");
		$this->pushMessageToAccount($room_id, $account_id, $msg_arr);	//有提示
		$msg_arr['data']['new_card'] = $has_new_card ? -1 : ""; //-1表示其他人只看到新牌的背面，空表示没有新牌
		$msg_arr['data']['hu_flag'] = ""; 
		$msg_arr['data']['gang_flag'] = ""; 
		$RoomUser_UID = strtr(Game::RoomUser_UID, $replyArr);
		$exclude_client_id = Gateway::getClientIdByUid($RoomUser_UID);
		$this->pushMessageToGroup($room_id, $msg_arr, $exclude_client_id); //非出牌人，提示为空
	}
	//通知用户碰杠
	protected function notyUserToPengGang($room_id, $account_id, $playing_status){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$mkv[Redis_Const::Play_Field_ActiveUser] = $account_id;
		$mkv[Redis_Const::Play_Field_ActiveType] = $playing_status;
		$mkv[Redis_Const::Play_Field_NewCard] = "";		//清空新牌
		$mset_result = $Redis_Model->hmsetField($Play_Key,$mkv);

		if($playing_status == 3){
			$this->writeLog("[$room_id] ($account_id) 通知碰");
		} else {
			$this->writeLog("[$room_id] ($account_id) 通知杠");
		}
		
		//设置自动碰杠定时器
		$this->setupPengGangPassiveTimer($room_id, $account_id);

		$noty_arr = array(
			'account_id' => $account_id,
			'playing_status' => $playing_status,
			'limit_time'	 => Game::LimitTime_PengGang,
			);
		$msg_arr = array("result"=>"0","operation"=>"NotyPengGang","data"=>$noty_arr,"result_message"=>"通知碰杠");

		$this->pushMessageToAccount($room_id, $account_id, $msg_arr);	

		$msg_arr['data']['playing_status'] = Game::PlayingStatus_Waiting;
		$msg_arr['data']['account_id'] = ""; //清空谁碰
		$RoomUser_UID = strtr(Game::RoomUser_UID, $replyArr);
		$exclude_client_id = Gateway::getClientIdByUid($RoomUser_UID);
		$this->pushMessageToGroup($room_id, $msg_arr, $exclude_client_id); //非出牌人，提示为空

	}

	//打完牌显示结果
	public function showWin($room_id, $winner_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);

		$players = array();
		$player_cards = array();
		$room_members = $this->queryRoomMembers($room_id);
		foreach ($room_members as $mem_id) {
			//手牌
			$cards = $this->queryPlayerCard($room_id, $mem_id);
			$player_cards[] = array(
				'account_id'=> $mem_id,
				'cards' => $cards
				); 
		}

		//$multiple = $this->queryMultiple($room_id);
		$base_score = $this->queryBaseScore($room_id);
		$horse_cards = array();
		
		if($winner_id > 0){

			$horse_multiple = 0;
			$setting = $this->queryRoomSetting($room_id);
			$horse_count = $setting[Redis_CONST::Room_Field_Horse];
			$is_explosive = $horse_count == 1 ? true : false;	//爆炸马

			$remain_count = $this->queryRemainCardCount($room_id);
			if($horse_count > 0 && $remain_count > 0){

				$RemainCard_Key = strtr(Redis_Const::RemainCard_Key, $replyArr);
				if($is_explosive){	//爆炸马

					$cards = $Redis_Model->popList(0 ,$RemainCard_Key,1);   //左边(队尾)弹出1张
					$value = $cards[0];

					$origin_value = $value;
					$explode_number = 1;
					if($value < 100){
						$value += 100;
					}
					$type = intval($value/10);
					if($type == 12 || $type == 14 || $type == 16){
						$explode_number = $value%10;
					} else if($type == 18 || $type == 19 ){
						$explode_number = 5;
					}
					$horse_cards[] = array("card"=>$origin_value, "win"=>$explode_number);

					$this->writeLog("[$room_id] 爆炸码乘数:".$explode_number);

					$horse_multiple = $explode_number - 1;

				} else {
					$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
					$winner_seat_number = $Redis_Model->getZscore($RoomSequence_Key, $winner_id);
					$banker_id = $this->queryBanker($room_id);
					$banker_seat_number = $Redis_Model->getZscore($RoomSequence_Key, $banker_id);
					$lucky_numer = ($winner_seat_number - $banker_seat_number + 4) % 4 + 1;
					$horse_count = $remain_count > $horse_count ? $horse_count : $remain_count;
					
					$cards = $Redis_Model->popList(0 ,$RemainCard_Key,$horse_count);   //左边(队尾)弹出N张

					foreach ($cards as $value) {
						$origin_value = $value;
						$is_lucky = 0;
						if($value < 100){
							$value += 100;
						}
						$type = intval($value/10);
						if($type == 12 || $type == 14 || $type == 16){
							if($value%10%4 == $lucky_numer%4){
								$is_lucky = 1;
								$horse_multiple++;
							}
						} else if($type == 18 ){
							if(($value%10)/3 + 1 == $lucky_numer){
								$is_lucky = 1;
								$horse_multiple++;
							}
						} else if($type == 19){
                            if(($value%10)/3  == $lucky_numer){
                                $is_lucky = 1;
                                $horse_multiple++;
                            }
                        }
						$horse_cards[] = array("card"=>$origin_value, "win"=>$is_lucky);
					}
					$this->writeLog("[$room_id] 中码个数:".$horse_multiple);
				}

			}
			
			$score = $base_score * 2 * ($horse_multiple + 1);

			$setting = $this->queryRoomSetting($room_id);
			$chengbao = isset($setting[Redis_Const::Room_Field_ChengBao]) ? $setting[Redis_Const::Room_Field_ChengBao] : 1;
			if($chengbao && $this->queryLastUserDanger($room_id)){
				$last_user_discard = $this->queryLastUserDiscard($room_id);
				$last_user = $last_user_discard['last_user'];

				$Redis_Model->hincrbyField($RoomScore_Key, $winner_id, $score * 3 );
				$Redis_Model->hincrbyField($Chip_Key, $winner_id, $score * 3 );

				$Redis_Model->hincrbyField($RoomScore_Key, $last_user,  - $score * 3);
				$Redis_Model->hincrbyField($Chip_Key, $last_user,  - $score * 3 );

			} else {
				foreach ($room_members as $mem_id) {
					if($mem_id == $winner_id){
						$Redis_Model->hincrbyField($RoomScore_Key, $mem_id, $score * 3 );
						$Redis_Model->hincrbyField($Chip_Key, $mem_id, $score * 3 );
					} else {
						$Redis_Model->hincrbyField($RoomScore_Key, $mem_id,  -$score );
						$Redis_Model->hincrbyField($Chip_Key, $mem_id,  -$score );
					}
				}
			}

			$Room_mkv[Redis_CONST::Room_Field_Banker] = $winner_id;	//庄家

		} else {	//黄了
			$winner_id = -1;
			$score = 0;
		}

		$scoreboard = $Redis_Model->hgetallField($RoomScore_Key);

		//保存积分榜
		if(is_array($scoreboard)){
			$ticket_checked_user = $this->queryTicketCheckedUser($room_id);
			foreach ($scoreboard as $key => $value) {
				if(!in_array($key, $ticket_checked_user)){
					//未扣房卡的用户不显示在积分榜上
					unset($scoreboard[$key]);
				}
			}
			$board_json_str = json_encode($scoreboard);

		} else {
			$scoreboard = array();
			$board_json_str = "";
		}
		$this->writeLog("[".$room_id."]积分榜:".$board_json_str);
		$Room_mkv[Redis_Const::Room_Field_Scoreboard] = $board_json_str;
		$Redis_Model->hmsetField($Room_Key,$Room_mkv);
		$MMYSQL = $this->initMysql();

		$score_summary = $Redis_Model->hgetallField($Chip_Key);	//每局输赢
		
		$start_time = $this->queryStartTime($room_id);
		$game_num = $this->queryGameNumber($room_id);
		$total_num = $this->queryTotalNum($room_id);
		$msg_arr = array(
			'result' => 0,
			'operation' => 'Win',
			'result_message' => "获胜+积分榜",
			'data' => array(
				'player_cards' => $player_cards,
				'win_card' => $this->queryNewCard($room_id),
				'winner_id' => $winner_id,

				'horse_cards' => $horse_cards,
				'score'  => $score,
				'score_board' => $scoreboard,
				'score_summary' => $score_summary,
				'game_num' => $game_num,
				'total_num' =>  $total_num
				)
			);
		$this->pushMessageToGroup($room_id, $msg_arr);

		//保存当局游戏结果
		$setting = $this->queryRoomSetting($room_id);
		$round = $setting[Redis_Const::Room_Field_GameRound];

		$game_info['room_id'] = $room_id;
		$game_info['game_type'] = Game::Game_Type;
		$game_info['dealer_num'] = Config::Dealer_Num;
		$game_info['round'] = $round;
		$game_info['game_num'] = $game_num;
		$game_info['total_num'] = $total_num;
		$game_info['extra'] = "";
//        $this->saveGameResult($game_info);
		$this->updateRoomStatus($room_id, 1);   //房间状态，1等待、2进行中、3关闭
		if($game_num == $total_num){  //最后一局

			$round = $Redis_Model->hincrbyField($Room_Key, Redis_Const::Room_Field_GameRound, 1);
			$this->writeLog("[$room_id] 第".($round-1)."轮 结束!");

			$name_board = array();
			foreach ($scoreboard as $account_id => $score) {
				$account_sql = 'select nickname from '.WX_Account.' where account_id ='.$account_id;
				$name = $MMYSQL->single($account_sql);
				$name_board[] = array('name'=>$name, 'score'=>$score, 'account_id'=>$account_id);
				
			}
			//规则文本
			$rule_text = $this->formatRuleText($room_id);
			$balance_scoreboard = array('time'=>time(), 'scoreboard'=>$name_board,'game_num'=>$game_num);
			$balance_board_json_str = json_encode($balance_scoreboard['scoreboard']);

			//保存积分榜
			$board_array['start_time'] = $start_time;
			$board_array['create_time'] = time();
			$board_array['is_delete'] = G_CONST::IS_FALSE;
			$board_array['game_type'] = Game::Game_Type;  //游戏6 广东麻将
			$board_array['room_id'] = $room_id;
			$board_array['round'] = $round-1;
			$board_array['game_num'] = $game_num;

			$board_array['rule_text'] = $rule_text;
			$board_array['board'] = $board_json_str;
			$board_array['balance_board'] = $balance_board_json_str;
			$board_id = $MMYSQL->insertReturnID(Room_Scoreboard,$board_array);

			//保存用户积分
			$game_info['score_board'] = $scoreboard;
			$this->saveAccountGameScore($game_info);

			//清理房间
			$this->clearRoom($room_id);
		
		} else {
			$this->resetAllAccountStatus($room_id);  //重设所有用户状态为未准备

			$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
			$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
			$DaiQiangGang_Key = strtr(Redis_Const::DaiQiangGang_Key, $replyArr);
			$YiQiangGang_Key = strtr(Redis_Const::YiQiangGang_Key, $replyArr);
			$RemainCard_Key = strtr(Redis_Const::RemainCard_Key, $replyArr);
			//删除每局游戏参数
			$Redis_Model->deleteKey($Play_Key);
			$Redis_Model->deleteKey($PlayMember_Key);
			$Redis_Model->deleteKey($DaiQiangGang_Key);
			$Redis_Model->deleteKey($YiQiangGang_Key);
			$Redis_Model->deleteKey($RemainCard_Key);
			//$Redis_Model->deleteKey($Chip_Key);  //因为游戏结束后刷新时还需获取当局积分，所有暂不删除，下一句开始时才删除
			for ($i=1; $i <= 4; $i++) { 
				$Redis_Model->deleteKey("PlayerCard:".$i.":".$room_id);
				$Redis_Model->deleteKey("PengCard:".$i.":".$room_id);
				$Redis_Model->deleteKey("MingGang:".$i.":".$room_id);
				$Redis_Model->deleteKey("AnGang:".$i.":".$room_id);
				$Redis_Model->deleteKey("Discard:".$i.":".$room_id);
			}

			if(Config::Room_AutoBreak){
				//3分钟未开局则解散
				$this->setupBreakRoomPassiveTimer($room_id);
			}
		}
	}

	function clearRoom($room_id){
		//清理房间
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);

		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
		
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
		$DaiQiangGang_Key = strtr(Redis_Const::DaiQiangGang_Key, $replyArr);
		$YiQiangGang_Key = strtr(Redis_Const::YiQiangGang_Key, $replyArr);
		$RemainCard_Key = strtr(Redis_Const::RemainCard_Key, $replyArr);
		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);

		//删除每轮游戏参数
		$Redis_Model->deleteKey($RoomSequence_Key);
		$Redis_Model->deleteKey($RoomScore_Key);
		$Redis_Model->deleteKey($AccountStatus_Key);
		$Redis_Model->deleteKey($TicketChecked_Key);
		//删除每局游戏参数
		$Redis_Model->deleteKey($Play_Key);
		$Redis_Model->deleteKey($PlayMember_Key);
		$Redis_Model->deleteKey($DaiQiangGang_Key);
		$Redis_Model->deleteKey($YiQiangGang_Key);
		$Redis_Model->deleteKey($RemainCard_Key);
		$Redis_Model->deleteKey($Chip_Key);
		for ($i=1; $i <= 4; $i++) { 
			$Redis_Model->deleteKey("PlayerCard:".$i.":".$room_id);
			$Redis_Model->deleteKey("PengCard:".$i.":".$room_id);
			$Redis_Model->deleteKey("MingGang:".$i.":".$room_id);
			$Redis_Model->deleteKey("AnGang:".$i.":".$room_id);
			$Redis_Model->deleteKey("Discard:".$i.":".$room_id);
		}
		if(Config::Room_IsReuse == 1){	//可以重复利用房间
			$Room_mkv[Redis_Const::Room_Field_GameNum] = 0;			//游戏局数
			$Room_mkv[Redis_CONST::Room_Field_Banker] = -1;	//庄家
			$Room_mkv[Redis_Const::Room_Field_Scoreboard] = "";		//积分榜清零
			$Room_mkv[Redis_Const::Room_Field_Creator] = -1;		//创建者清空
			$Room_mkv[Redis_Const::Room_Field_Status] = Game::RoomStatus_Closed;	//房间状态，1等待、2进行中、3未激活
			$Room_mkv[Redis_Const::Room_Field_StartTime] = -1;
			$mset_result = $Redis_Model->hmsetField($Room_Key,$Room_mkv);
		} else {  //玩一轮即销毁
			$MMYSQL = $this->initMysql();
			$MMYSQL->update(Room)->set('is_close', '1')->where('room_id='.$room_id)->query();

			$Redis_Model->deleteKey($Room_Key);
		}
		$this->writeLog("[$room_id] 房间清理完毕!");
	}

	//整理规则内容文本
	protected function formatRuleText($room_id,$room_data="")
	{
		$rule_text = "";
		$setting = $this->queryRoomSetting($room_id);
		$joker =isset($setting[Redis_Const::Room_Field_Joker]) ?$setting[Redis_Const::Room_Field_Joker]:0;
		$horse_count =isset($setting[Redis_Const::Room_Field_Horse]) ?$setting[Redis_Const::Room_Field_Horse]:0;
		$ticket_count = isset($setting[Redis_Const::Room_Field_TicketCount]) ?$setting[Redis_Const::Room_Field_TicketCount]:1;
		$qianggang =isset($setting[Redis_Const::Room_Field_QiangGang]) ?$setting[Redis_Const::Room_Field_QiangGang]:1;
		$chengbao =isset($setting[Redis_Const::Room_Field_ChengBao]) ?$setting[Redis_Const::Room_Field_ChengBao]:1;

		//局数房卡规则
		$ticket_type_text = (Config::GameNum_EachRound * $ticket_count)."局/".$ticket_count."张房卡";
		$rule_text .= $ticket_type_text;

		//底分
		$rule_text .= ",";
		switch($joker)
		{
			case 0:
				$rule_text .= "无鬼牌";
				break;
			case 1:
				$rule_text .= "翻牌当鬼";
				break;
			case 2:
				$rule_text .= "红中当鬼";
				break;
		}

		if($qianggang )
		{
			$rule_text .= ",抢杠全包";
		}
		if($chengbao )
		{
			$rule_text .= ",杠爆全包";
		}

		//抓码
		$rule_text .= ",抓马:";
		switch($horse_count)
		{
			case 0:
				$rule_text .= "不跑马";
				break;
			case 2:
			case 4:
			case 6:
			case 8:
				$rule_text .= $horse_count."匹";
				break;
			case 1:
				$rule_text .= "爆炸马";
				break;
		}

		return $rule_text;
	}
	protected function saveAccountGameScore($game_info)
	{
		if(Config::Is_SendGameScore == 0){
			return ;
		}
		
		$game_type = $game_info['game_type'];
		$dealer_num = $game_info['dealer_num'];

		$game_result['time'] = time();
		$game_result['rid'] = $game_info['room_id'];
		$game_result['rnd'] = $game_info['round'];
		$game_result['board'] = $game_info['score_board'];
		
		$game_result_str = json_encode($game_result);
		$push_array = array($game_result_str);

		//连接日志系统
		$Redis_Model = Redis_Model::getModelObjectLogs();
		$replyArr = array("[dealernum]"=>$dealer_num,"[gametype]"=>$game_type);

		$GameScore_Key = strtr(Redis_Const::GameScore_Key, $replyArr);
		$push_result = $Redis_Model->pushListLogs($is_rpush=0,$is_pushx=0,$GameScore_Key,$push_array); //lpush


		//推送到结果处理器
		$msg_array = array(
				'operation' => "PullGameScore",
				'dealer_num'   => $dealer_num,
				'game_type'   => $game_type,
				'data' => array(
					)
				);
		$this->sendToGameResultProcessor($msg_array);

		return true;
	}

	/*
		推推送给游戏结果处理器
	*/
	public function sendToGameResultProcessor($msg_array="")
	{
		$message = $this->_JSON($msg_array);

		$socket_name = "Processor";
		$Socket_Model = Socket_Model::getModelObject($socket_name);
		$Socket_Model->sendMessageToSocket($socket_name,$message);

		return true;
	}


	/*
		推给定时器服务器
	*/
	public function sendToTimerServer($msg_array = "")
	{
		$message = $this->_JSON($msg_array);

		$socket_name = "Timer";
		$Socket_Model = Socket_Model::getModelObject($socket_name);
		$Socket_Model->sendMessageToSocket($socket_name,$message);

		return true;
	}


	/*
		数组转JSON格式
	*/
	protected function _JSON($array) 
	{  
		$this->__arrayRecursive($array, 'urlencode', true);  
		$json = json_encode($array);  
		return urldecode($json);  
	}
	private function __arrayRecursive(&$array, $function, $apply_to_keys_also = false)  
	{  
		static $recursive_counter = 0;  
		if (++$recursive_counter > 1000) {  
			return false;
			die('possible deep recursion attack');  
		}  
		foreach ($array as $key => $value) {  
			if (is_array($value)) {  
				$this->__arrayRecursive($array[$key], $function, $apply_to_keys_also);  
			}
			else if(is_object($value))
			{
				$array[$key] = $value;
			} 
			else 
			{  
				$array[$key] = $function($value);  
			}  
	   
			if ($apply_to_keys_also && is_string($key)) {  
				$new_key = $function($key);  
				if ($new_key != $key) {  
					$array[$new_key] = $array[$key];  
					unset($array[$key]);  
				}  
			}  
		}  
		$recursive_counter--;
	}   
	
	/**
    * 拆解接收的json字符串
    * @param string $splitJsonString json字符串
    */
	protected function _splitJsonString($jsonString)
	{
		if(empty($jsonString))
		{
			return OPT_CONST::JSON_FALSE;
		}
		//判断是否为JSON格式
		if(is_null(json_decode($jsonString)))
		{
			//不是json格式
			return OPT_CONST::JSON_FALSE;
		}
		else
		{
			//分拆JSON字符串
			return json_decode($jsonString,true);
		}
	}
	
	
	/*
		返回缺参结果
	*/
	protected function _missingPrameterArr($operation,$prameter)
	{
		return array('result'=>OPT_CONST::MISSING_PARAMETER,'operation'=>$operation,'data'=>array("missing_parameter"=>$prameter),'result_message'=>"缺少参数");
	}
	
	
	
	/*
		判断数据格式是否正确
	*/
	protected function _checkRequestFormat($requestAry)
	{
		if(!isset($requestAry['msgType']))
		{
			$this->logMessage('error', "function(checkRequestFormat):lack of msgType"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>"",'data'=>array("missing_parameter"=>"msgType"),'result_message'=>"缺少参数");
		}
		if(!isset($requestAry['content']))
		{
			$this->logMessage('error', "function(checkRequestFormat):lack of content"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>"",'data'=>array("missing_parameter"=>"content"),'result_message'=>"缺少参数");
		}
		
		return OPT_CONST::POSTARRAY_TRUE;
	}
	
	
	/*
		判断数据格式是否正确
	*/
	protected function _checkPostArray($postArr)
	{
		
		if(!isset($postArr['operation']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of operation"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>"",'data'=>array("missing_parameter"=>""),'result_message'=>"缺少参数");
		}
		else $operation = $postArr['operation'];
		if(!isset($postArr['data']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of data"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>$operation,'data'=>array("missing_parameter"=>""),'result_message'=>"缺少参数");
		}
		if(!isset($postArr['account_id']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of account_id"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>$operation,'data'=>array("missing_parameter"=>""),'result_message'=>"缺少参数");
		}
		if(!isset($postArr['session']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of session"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>$operation,'data'=>array("missing_parameter"=>""),'result_message'=>"缺少参数");
		}
		return OPT_CONST::POSTARRAY_TRUE;
	}
	
	
	
	/*
		生成微秒
	*/
	protected function getMicroTimestamp()
	{
		$mtime=explode(' ',microtime());
		$mTimestamp=$mtime[1] . substr($mtime[0],2,3);
		
		return $mTimestamp;
	}
	
	/*
		判断请求链接合法性
	*/
	protected function checkRequestClientLegal($client_id,$room_id,$account_id)
	{
		return true;
		//绑定用户UID
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$room_aid = strtr(Game::RoomUser_UID, $replyArr);

		$client_array = Gateway::getClientIdByUid($room_aid);
		if(is_array($client_array) && count($client_array) > 0)
		{
			foreach($client_array as $bind_client)
			{
				if($bind_client == $client_id)
				{
					return true;
				}
			}
		}
		return false;
	}
	
}
?>